package ve.com.ucv.changedetection.model;

import ve.com.ucv.changedetection.objects.*;
import ve.com.ucv.changedetection.tools.SetOperations;

import javax.swing.plaf.basic.BasicInternalFrameTitlePane;
import java.text.DecimalFormat;
import java.util.*;

/**
 * Created with IntelliJ IDEA.
 * User: josmaguirre
 * Date: 5/12/12
 * Time: 8:56
 * To change this template use File | Settings | File Templates.
 */
public class HashingBasedImplementation {
    public TreeNode oldAbstractTree;
    public TreeNode newAbstractTree;
    public HashTable generatedOldURLHashTable;
    public SubtreeTable generatedOldURLSubtreeTable;
    public HashTable generatedNewURLHashTable;
    public SubtreeTable generatedNewURLSubtreeTable;
    public ArrayList<LookupTable> lookupTable;
    public int index;
    public TemporaryTable temporaryTable;
    public double contentCoef, attrCoef, structCoef;

    public HashingBasedImplementation(TreeNode oldURLTree, TreeNode newURLTree, double contentCoef, double attrCoef, double structCoef){
        this.oldAbstractTree = oldURLTree;
        this.newAbstractTree = newURLTree;
        this.generatedOldURLHashTable = new HashTable();
        this.generatedNewURLHashTable = new HashTable();
        this.generatedOldURLSubtreeTable = new SubtreeTable();
        this.generatedNewURLSubtreeTable = new SubtreeTable();
        this.lookupTable = new ArrayList<LookupTable>();
        this.temporaryTable = new TemporaryTable();
        this.index = 0;
        this.contentCoef = contentCoef;
        this.attrCoef = attrCoef;
        this.structCoef = structCoef;
    }

    public void generateComparisonTables(){
        generateOldURLTables(this.oldAbstractTree);
        //Inicializando el indice para la generacion de los arboles
        setIndex(0);
        generateNewURLTables(this.newAbstractTree);
        generateNewURLLookupTable();
    }

    public void generateOldURLTables(TreeNode tree){
        SubtreeRow treeRow = new SubtreeRow();
        HashRow row = new HashRow();
        row.setRow(this.index);
        row.setNodeId(this.index + 1);
        row.setNode(tree.getNodeName());
        row.setType(tree.getNodeType());
        row.setAttributes(tree.getAttributes());
        row.setWeight(tree.getNodeValue());
        this.generatedOldURLHashTable.setRow(row);

        if (tree.getDepth() == 3){
            treeRow.setMark(tree.getNodeName());
            treeRow.setStartId(row.getNodeId());
        }
        index++;

        if (tree.getChildNodes().size() != 0){
            for (int i = 0; i < tree.getChildNodes().size(); i++){
                generateOldURLTables(tree.getChildNodes().get(i));
            }
        }

        if (tree.getDepth() == 3){
            treeRow.setEndId(this.index);
            this.generatedOldURLSubtreeTable.addSubtreeRow(treeRow);
        }
    }

    public void generateNewURLTables(TreeNode tree){
        SubtreeRow treeRow = new SubtreeRow();
        HashRow row = new HashRow();
        row.setRow(this.index);
        row.setNodeId(this.index + 1);
        row.setNode(tree.getNodeName());
        row.setType(tree.getNodeType());
        row.setAttributes(tree.getAttributes());
        row.setWeight(tree.getNodeValue());
        this.generatedNewURLHashTable.setRow(row);

        if (tree.getDepth() == 3){
            treeRow.setMark(tree.getNodeName());
            treeRow.setStartId(row.getNodeId());
        }

        index++;
        if (tree.getChildNodes().size() != 0){
            for (int i = 0; i < tree.getChildNodes().size(); i++){
                generateNewURLTables(tree.getChildNodes().get(i));
            }

        }

        if (tree.getDepth() == 3){
            treeRow.setEndId(this.index);
            this.generatedNewURLSubtreeTable.addSubtreeRow(treeRow);
        }
    }

    public void generateNewURLLookupTable(){
        // Creando el Lookup table de la pagina actual
        for (int i = 0; i < this.generatedNewURLSubtreeTable.getSubtreeRows().size(); i++){
            //Verifico por cada elemento de la tabla de sub-arboles si este existe en la lookup table
            int isInLookupTable = isInLookupTable(this.generatedNewURLSubtreeTable.getSubtreeRows().get(i).getMark());
            if (isInLookupTable != -1){
                this.lookupTable.get(isInLookupTable).references.add(i);
            }else{
                LookupTable lt = new LookupTable();
                lt.setMark(this.generatedNewURLSubtreeTable.getSubtreeRows().get(i).getMark());
                lt.addReference(i);
                lookupTable.add(lt);
            }
        }
    }

    public int isInLookupTable(String mark){
        //Aqui se recorre la lookup table, si no se encuentra una ocurrencia de la marca, se retorna -1, de lo contrario
        //se retorna la posicion en la lookup table donde se encuentra la marca

        int position = -1, index = 0;
        while ((position == -1) && (index < this.lookupTable.size())){
            if (this.lookupTable.get(index).getMark().equals(mark)){
                position = index;
            }
            index++;
        }
        return position;
    }

    public boolean initComparison(){
        //INICIO COMPARACION DE CONTENIDOS DE LAS PAGINAS
        //SE RECORRE LA TABLA DE SUB ARBOLES DE LA PAGINA ANTERIOR
        for (int i = 0; i < this.generatedOldURLSubtreeTable.getSubtreeRows().size(); i++){
            //SE OBTIENE LA FILA DE LA TABLA DE SUB ARBOLES DE LA PAGINA ANTERIOR
            SubtreeRow oldSubtreeRow = this.generatedOldURLSubtreeTable.getSubtreeRow(i);
            //SE OBTIENE LA LISTA DE REFERENCIAS DE LA TABLA LOOKUP QUE TENGA LA MISMA MARCA
            ArrayList<Integer> references = getLookupTableReferences(oldSubtreeRow.getMark());
            //ArrayList<String> wordsInOldURL = getContent(oldSubtreeRow.getStartId(), oldSubtreeRow.getEndId());

            int oldEndId = oldSubtreeRow.getEndId();
            int oldStartId = oldSubtreeRow.getStartId();

            for (int index = oldStartId; index < oldEndId ; index++ ){
                HashRow oldNode = this.generatedOldURLHashTable.getRow(index);
                TemporaryRow temporaryRow = new TemporaryRow();
                double max = -1;

                for(int j = 0; j < references.size(); j++){
                    int newEndId = this.generatedNewURLSubtreeTable.getSubtreeRow(references.get(j)).getEndId();
                    int newStartId = this.generatedNewURLSubtreeTable.getSubtreeRow(references.get(j)).getStartId();

                    for(int index2 = newStartId; index2 < newEndId; index2++){
                        HashRow newNode = this.generatedNewURLHashTable.getRow(index2);

                        double intersect = 0, attDistResult = 0, typeDistResult = 0, CS = 0;

                        //REALIzANDO LA COMPARACION DE CONTENIDO
                        ArrayList<String> oldWords = getWordsArray(oldNode.getWeight());
                        ArrayList<String> newWords = getWordsArray(newNode.getWeight());

                        if (SetOperations.getWordsUnion(oldWords, newWords).size() != 0){
                            intersect = (double)SetOperations.getWordsIntersection(oldWords, newWords).size() / (double)SetOperations.getWordsUnion(oldWords, newWords).size();
                        }else{
                            intersect = 1;
                        }

                        //REALIZANDO LA COMPARACION DE LOS ATRIBUTOS
                        Set attUnion = SetOperations.getAttributesUnion(oldNode.getAttributes(), newNode.getAttributes());
                        Set attIntersect = SetOperations.getAttributesUnion(oldNode.getAttributes(), newNode.getAttributes());

                        if(attUnion.size() != 0){
                            //attDistResult = (double)SetOperations.getAttributesIntersection(oldNode.getAttributes(), newNode.getAttributes()).size() /
                            //          (double)SetOperations.getAttributesUnion(oldNode.getAttributes(), newNode.getAttributes()).size();
                            attDistResult = (double)SetOperations.getWeightsSum(attIntersect) / (double)SetOperations.getWeightsSum(attUnion);
                        }else{
                            attDistResult = 1;
                        }

                        //REALIZANDO LA COMPARACION DE MARCAS
                        int common = SetOperations.getCommonMarks(getMarks(oldNode.getType()), getMarks(newNode.getType()));
                        int maximum = SetOperations.getMaximum(getMarks(oldNode.getType()), getMarks(newNode.getType()));
                        typeDistResult = SetOperations.getTypeDist(common, maximum);

                        //CALCULANDO COEFICIENTE DE SIMILARIDAD
                        CS = -1 + 2 * (this.structCoef * typeDistResult + this.attrCoef * attDistResult + this.contentCoef * intersect);

                        if (CS > max){
                            System.out.println("TypeDistResult: " + this.structCoef + "  attDistResult: " + this.attrCoef * attDistResult + " intersect: " + this.contentCoef * intersect);
                            temporaryRow.setNodeId1(oldNode.getNodeId());
                            temporaryRow.setNodeId2(newNode.getNodeId());
                            temporaryRow.setWeightPosition(SetOperations.getWordsIntersection(oldWords, newWords).size());
                            temporaryRow.setWeightTotal(SetOperations.getWordsUnion(oldWords, newWords).size());
                            temporaryRow.setAttribute(attDistResult);
                            temporaryRow.setCS(CS);
                            max = CS;
                        }
                    }
                }
                temporaryTable.addRow(temporaryRow);
            }
        }

        return true;
    }

    public ArrayList<String> getMarks(String path){
        ArrayList<String> marks = new ArrayList<String>();
        StringTokenizer token = new StringTokenizer(path, ";");
        while(token.hasMoreTokens()){
            marks.add(token.nextToken());
        }
        return marks;
    }

    public ArrayList<String> getWordsArray(String weight){
        ArrayList<String> words = new ArrayList<String>();

        if (weight != null){
            StringTokenizer token = new StringTokenizer(weight, " ");
            while (token.hasMoreTokens()){
                words.add(token.nextToken());
            }
        }
        return words;

    }

    public ArrayList<Integer> getLookupTableReferences(String mark){
        for (int i = 0; i < getLookupTable().size(); i++){
            if(getLookupTable().get(i).getMark().equals(mark)){
                return getLookupTable().get(i).getReferences();
            }
        }
        return null;
    }

    public double getSimilarityCoeficient(){
        double numerator = 0;
        int denominator = this.temporaryTable.getTemporaryRows().size();

        //CALCULANDO EL COEFICIENTE DE SIMILARIDAD DE LA COMPARACION DE LA PAGINA WEB
        for(int i = 0; i < this.temporaryTable.getTemporaryRows().size(); i++){
            numerator += this.temporaryTable.getTemporaryRows().get(i).getCS();
        }

        //DecimalFormat df = new DecimalFormat("#,######");
        //System.out.println(df.format(numerator/denominator));
        return  (numerator/denominator);
    }

    public boolean isDifferences(double similarityCoef){
        if (getSimilarityCoeficient() < similarityCoef)
            return true;
        return false;
    }

    public TreeNode getOldAbstractTree() {
        return oldAbstractTree;
    }

    public void setOldAbstractTree(TreeNode oldAbstractTree) {
        this.oldAbstractTree = oldAbstractTree;
    }

    public TreeNode getNewAbstractTree() {
        return newAbstractTree;
    }

    public void setNewAbstractTree(TreeNode newAbstractTree) {
        this.newAbstractTree = newAbstractTree;
    }

    public HashTable getGeneratedOldURLHashTable() {
        return generatedOldURLHashTable;
    }

    public void setGeneratedOldURLHashTable(HashTable generatedOldURLHashTable) {
        this.generatedOldURLHashTable = generatedOldURLHashTable;
    }

    public SubtreeTable getGeneratedOldURLSubtreeTable() {
        return generatedOldURLSubtreeTable;
    }

    public void setGeneratedOldURLSubtreeTable(SubtreeTable generatedOldURLSubtreeTable) {
        this.generatedOldURLSubtreeTable = generatedOldURLSubtreeTable;
    }

    public HashTable getGeneratedNewURLHashTable() {
        return generatedNewURLHashTable;
    }

    public void setGeneratedNewURLHashTable(HashTable generatedNewURLHashTable) {
        this.generatedNewURLHashTable = generatedNewURLHashTable;
    }

    public SubtreeTable getGeneratedNewURLSubtreeTable() {
        return generatedNewURLSubtreeTable;
    }

    public void setGeneratedNewURLSubtreeTable(SubtreeTable generatedNewURLSubtreeTable) {
        this.generatedNewURLSubtreeTable = generatedNewURLSubtreeTable;
    }

    public ArrayList<LookupTable> getLookupTable() {
        return lookupTable;
    }

    public void setLookupTable(ArrayList<LookupTable> lookupTable) {
        this.lookupTable = lookupTable;
    }

    public int getIndex() {
        return index;
    }

    public void setIndex(int index) {
        this.index = index;
    }

    public TemporaryTable getTemporaryTable() {
        return temporaryTable;
    }

    public void setTemporaryTable(TemporaryTable temporaryTable) {
        this.temporaryTable = temporaryTable;
    }

    public double getContentCoef() {
        return contentCoef;
    }

    public void setContentCoef(double contentCoef) {
        this.contentCoef = contentCoef;
    }

    public double getAttrCoef() {
        return attrCoef;
    }

    public void setAttrCoef(double attrCoef) {
        this.attrCoef = attrCoef;
    }

    public double getStructCoef() {
        return structCoef;
    }

    public void setStructCoef(double structCoef) {
        this.structCoef = structCoef;
    }
}
